#ifndef _PTHREADTYPE_H_
#define _PTHREADTYPE_H_

#include "list.h"
#include "sched.h"

enum {
    /*
     * If the mutex type is PTHREAD_MUTEX_NORMAL, deadlock detection shall not be provided.
     * Attempting to relock the mutex causes deadlock. If a thread attempts to unlock a mutex that it
     * has not locked or a mutex which is unlocked, undefined behavior results.
     */
    PTHREAD_MUTEX_NORMAL = 0,

    /*
     * If the mutex type is PTHREAD_MUTEX_ERRORCHECK, then error checking shall be provided.
     * If a thread attempts to relock a mutex that it has already locked, an error shall be returned. If a
     * thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked, an error
     * shall be returned.
     */
    PTHREAD_MUTEX_ERRORCHECK,

    /*
     * If the mutex type is PTHREAD_MUTEX_RECURSIVE, then the mutex shall maintain the
     * concept of a lock count. When a thread successfully acquires a mutex for the first time, the lock
     * count shall be set to one. Every time a thread relocks this mutex, the lock count shall be
     * incremented by one. Each time the thread unlocks the mutex, the lock count shall be
     * decremented by one. When the lock count reaches zero, the mutex shall become available for
     * other threads to acquire. If a thread attempts to unlock a mutex that it has not locked or a mutex
     * which is unlocked, an error shall be returned.
     */
    PTHREAD_MUTEX_RECURSIVE,

    /*
     * If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex
     * results in undefined behavior. Attempting to unlock the mutex if it was not locked by the calling
     * thread results in undefined behavior. Attempting to unlock the mutex if it is not locked results in
     * undefined behavior.
     */
    PTHREAD_MUTEX_DEFAULT
};

enum {
    /*
     * If the mutex protocol is PTHREAD_PRIO_NONE, thread priority and shedulering will not be affectd
     * by mutex ownership.
     */
    PTHREAD_PRIO_NONE = 0,
    
    /*
     * If the mutex protocol is PTHREAD_PRIO_INHERIT, when threads with a higher priority take the mutex
     * which is take by thread "td1" with a lower priority, the thread "td1" will run as the highest priority
     * of the threads waiting for the mutex.
     */
    PTHREAD_PRIO_INHERIT,
    PTHREAD_PRIO_PROTECT,
};


enum {
    PTHREAD_CREATE_DETACHED = 0,
    PTHREAD_CREATE_JOINABLE
};

enum {
    PTHREAD_INHERIT_SCHED = 0,
    PTHREAD_EXPLICIT_SCHED
};

enum {
    PTHREAD_SCOPE_PROCESS = 0,
    PTHREAD_SCOPE_SYSTEM
};

#if !defined(CONFIG_PTHREAD_PRIORITY_MIN) && !defined(CONFIG_PTHREAD_PRIORITY_MAX)
    enum {
        PTHREAD_PRIORITY_MIN = 0,
        PTHREAD_PRIORITY_MAX = 31,
    
        PTHREAD_PRIORITY_NUM
    };
#else
    #define PTHREAD_PRIORITY_MIN CONFIG_PTHREAD_PRIORITY_MIN
    #define PTHREAD_PRIORITY_MAX CONFIG_PTHREAD_PRIORITY_MAX
    #define PTHREAD_PRIORITY_NUM CONFIG_PTHREAD_PRIORITY_MAX + 1
#endif

#ifndef CONFIG_PTHREAD_MUTEX_RECURSIVE_MAX
    #define PTHREAD_MUTEX_RECURSIVE_MAX 32
#else
    #define PTHREAD_MUTEX_RECURSIVE_MAX CONFIG_PTHREAD_MUTEX_RECURSIVE_MAX
#endif

typedef struct pthread_attr                 pthread_attr_t;
typedef struct pthread_spinlock             pthread_spinlock_t;

/*
 *  the definition of mutex and mutex data type
 */
typedef unsigned short                      mutex_count_t;

typedef struct pthread_mutex                pthread_mutex_t;

typedef struct pthread_mutexattr            pthread_mutexattr_t;

#define PTHREAD_SPINLOCK_INITIALIZER() \
    { \
        0, \
        NULL, \
    }
    
#define DEFINE_SPINLOCK(spinlock) \
    pthread_spinlock_t spinlock = PTHREAD_SPINLOCK_INITIALIZER();

#define PTHREAD_MUTEX_INITIALIZER(mutex) \
    { \
        LIST_HEAD_INIT((mutex).wait_list), \
        PTHREAD_SPINLOCK_INITIALIZER(), \
        NULL, \
    }

#define DEFINE_MUTEX(mutex) \
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER(mutex);

/* type of thread attribute*/
struct pthread_attr {

    /*
     * If the thread "detachstate" is "PTHREAD_CREATE_DETACHED", the thread will not be
     * blocked by its son thread which is created by it, or its "detachstate" is
     * PTHREAD_CREATE_JOINABLE, the thread should will be blocked by its son thread
     * until its son thread ends.
     */
    int detachstate;

    /*
     * thread scheduler policy
     */
    int  schedpolicy;

    /*
     * thread scheduler policy parameter
     */
    struct sched_param schedparam;

    /*
     * The thread inherit its father thread's scheduler police if the "schedpolicy" is
     * PTHREAD_INHERIT_SCHED. Otherwise it will inherit system scheduler policy, if
     * the "schedpolicy" is PTHREAD_EXPLICIT_SCHED
     */
    int inheritsched;

    /*
     * If "scope" is PTHREAD_SCOPE_PROCESS, the thread will just competitive for thread's
     * resource. Otherwise If the scope is PTHREAD_SCOPE_SYSTEM ,it will competitive for
     * the system resource.
     */
    int scope;

    /*
     * the stack overflow buffer size
     */
    size_t guardsize;

    /*
     * Check it the thread's stack is able to be set
     */
    int stackaddr_set;

    /*
     * The thread stack point, align for system hardware and OS bits
     */
    void *stackaddr;

    /*
     * The thread stack size, computed by bytes
     */
    size_t stacksize;
};

/*
 * spinlock structure description
 */
struct pthread_spinlock {

    /* spin lock counter */
    phys_reg_t lock;

    /* mutex lock owner(which thread) */
    void *task;
};

/*
 * the thread mutex attribute structure description
 */
struct pthread_mutexattr {

    /* thread mutex type: PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_ERRORCHECK, 
     *                    PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_DEFAULT
     */
    int type;

    /* thread mutex protocol: PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_ERRORCHECK, 
     *                    PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_DEFAULT
     */    
    int protocol;
};

/*
 * mutex structure description
 */
struct pthread_mutex {
    /* the list which is insert the suspend thread */
    list_t wait_list;

    pthread_spinlock_t wait_lock;

    /* mutex lock owner(which thread) */
    void *owner;

    struct pthread_mutexattr attr;

    union {
        /* recursive count */
        size_t count;
    } param;
};

#endif

